/**
 * @class   wosh::Utilities
 * @brief   Common (static) methods grouped into Utilities class.
 *
 ****************************************************************************
 * @version 0.8.462 $Id: Utilities.h 2829 2010-08-02 20:45:47Z alex $
 * @author  Alessandro Polo
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

#ifndef __WOSH_Core_Utilities_H__
 #define __WOSH_Core_Utilities_H__

 #include <woshDefs.h>
 #include <string>
 #include <vector>
 #include <cstdlib>
 #include <sstream>


namespace wosh {

class Utilities
 {

/** @name Math Functions
 * @{
 ******************************************************************************/
	public:
		/**
		 * @brief  Create a random number.
		 * @return random long integer
		 * @note   Implementation initializes srand() and calls rand()
		 */
		static long randomLong();

		/**
		 * @brief  Create a random number.
		 * @return random integer
		 * @note   Implementation initializes srand() and calls rand()
		 */
		static int randomInt();


		static int64 randomInt64();

		static double randomDouble();
		static int randomInt( int min, int max_limit );

//@}
/** @name Time Functions
 * @{
 ******************************************************************************/
	public:
		/**
		 * @brief  Get current epoch (of the system).
		 * @return number of seconds afer 1970 as positive long value
		 * @note   Implementation initializes srand() and calls time(NULL)
		 */
		static long std_time();

		/**
		 * @brief  Get current epoch (of the system) with millisecond precision.
		 * @return number of milliseconds afer 1970 as positive long value
		 * @note   time(NULL)
		 */
		static int64 std_time_ms();

		static std::string getTimeStampUTF( unsigned long epoch );

		static void getTimeStampUTF( char* buffer, int maxlen, unsigned long epoch );

		static void getTimeStamp( char* buffer, int maxlen, const char* format, unsigned long epoch );

		static std::string getTimeSpan( int64 epoch_milliseconds );
		static int64 parseTimeSpan( const std::string& timespan_millisec );

		static unsigned long parseTimeStampUTF( const std::string& utf_ts );

//@}
/** @name Conversion Functions (Strings)
 * @{
 ******************************************************************************/
	public:

		template<typename T_OUTPUT>
		static T_OUTPUT fromString( const std::string& value, const T_OUTPUT& def_value, std::ios_base& (*ios_format)(std::ios_base&) = std::nounitbuf ) {
			T_OUTPUT val = def_value;
			std::istringstream iss(value);
			if ( (iss >> ios_format >> val).fail() )
				return def_value;
			return val;
		 }
		// STRING->BOOL specialized impementation
		static bool fromString( const std::string& value, const bool& def_value ) {
			if ( value == "true" || value == "TRUE" || value == "yes" || value == "YES" || value == "on" || value == "ON" )
				return 1;
			if ( value == "false" || value == "FALSE" || value == "no" || value == "NO" || value == "off" || value == "OFF" )
				return 0;
			int asInt = fromString<int>(value, -1);
			if ( asInt == -1 )
				return def_value;
			return (asInt != 0);
		 }

		// STRING->BOOL specialized impementation
		static bool fromString( bool& value_out, const std::string& value ) {
			if ( value == "1" || value == "true" || value == "TRUE" || value == "yes" || value == "YES" || value == "on" || value == "ON" )
				value_out = true;
			else if ( value == "0" || value == "false" || value == "FALSE" || value == "no" || value == "NO" || value == "off" || value == "OFF" )
				value_out = false;
			else {
				int asInt = fromString<int>(value, -1);
				if ( asInt == -1 )
					return false;
				return (asInt != 0);
			 }
			return true;
		 }
		template<typename T_OUTPUT>
		static bool fromString( T_OUTPUT& value_out, const std::string& value ) {
			std::istringstream iss(value);
			return ( (iss >> value_out).fail() == false );
		 }

		template<typename T_OUTPUT>
		static T_OUTPUT fromString( const std::string& value ) {
			T_OUTPUT tempOut;
			std::istringstream iss(value);
			iss >> tempOut;
			return tempOut;
		 }
		// STRING->BOOL specialized impementation
	//	template<>
		static bool fromString( const std::string& value ) {
			bool out_value = false;
			if ( isBoolean( value, out_value ) )
				return out_value;
			return (fromString<int>(value, -1) != 0);
		 }

		template<typename T_INPUT>
		static std::string toString( const T_INPUT& value, const std::string& def_value, std::ios_base& (*format)(std::ios_base&) = std::nounitbuf ) {
			std::ostringstream oss;
			if ( (oss << format << value).fail() )
				return def_value;
			return oss.str();
		 }
		template<typename T_INPUT>
		static bool toString( std::string& value_out, const T_INPUT& value ) {
			std::ostringstream oss;
			bool fail = (oss << value).fail();
			if ( fail )
				return false;
			value_out = oss.str();
			return true;
		 }
		static bool toString( std::string& value_out, const bool& value ) {
			if ( value )
				value_out = "true";
			value_out = "false";
			return true;
		 }
		static std::string toString( const bool& value ) {
			if ( value )
				return "true";
			return "false";
		 }
		template<typename T_INPUT>
		static std::string toString( const T_INPUT& value ) {
			std::ostringstream oss;
			oss << value;
			return oss.str();
		 }

		static bool isNumerical( const std::string& value ) {
			int val;
			std::istringstream iss(value);
			return ( !(iss >> std::dec >> val).fail() );
		 }

		static bool isBoolean( const std::string& value, bool& out_value ) {
			if ( value == "true" || value == "TRUE" || value == "yes" || value == "YES" || value == "on" || value == "ON" )
				return out_value = true;
			else if ( value == "false" || value == "FALSE" || value == "no" || value == "NO" || value == "off" || value == "OFF" )
				return out_value = false;
			return false;
		 }

static void hex2string( std::string& hex_output, const char* hex_source, int size, const std::string& sep = "", unsigned short align = 2 );

static char* string2hex( int& outputsize, const std::string& hex_input, unsigned int align = 2, unsigned int sep_size = 0 );



//@}
/** @name String Functions
 * @{
 ******************************************************************************/
	public:
		static void toLower( std::string& str );
		static std::string toLower( const std::string& str );

		static void toUpper( std::string& str );
		static std::string toUpper( const std::string& str );


		static int replace( std::string& input,  const std::string& find_me,  const std::string& replaced_with );
		static std::string format( const char* format, ... );

		static void trimSpaces( std::string& str, short how = 0 );
		static void trimEndLine( std::string& str, short how = 0 );

		static short isNumeric( const char* str );
		static short evalRegexWildChar( const std::string& str_regext, const std::string& str_data );

		static bool popWordFromString( std::string& strdata, std::string& word, const std::string& separator = " " );
		static bool extractWordFromString( const std::string& strdata, std::string& word, const std::string& separator = " " );

		static std::string joinVector( const std::vector<std::string>& str_vector, std::string sep, int offset = 0 );

		// buggy?
	//	static int splitString(const std::string& input, char delimiter, std::vector<std::string>& results, bool includeEmpties = true );

		// original code by 'Paul J. Weiss' [http://www.codeproject.com/KB/string/stringsplit.aspx]
		static int splitString(const std::string& input, const std::string& delimiter, std::vector<std::string>& results, bool includeEmpties = true, bool trimResult = false );

/*

vector<string> split(const string& s, const string& delim, const bool keep_empty = true) {
    vector<string> result;
    if (delim.empty()) {
        result.push_back(s);
        return result;
    }
    string::const_iterator substart = s.begin(), subend;
    while (true) {
        subend = search(substart, s.end(), delim.begin(), delim.end());
        string temp(substart, subend);
        if (keep_empty || !temp.empty()) {
            result.push_back(temp);
        }
        if (subend == s.end()) {
            break;
        }
        substart = subend + delim.size();
    }
    return result;
}


		template < class ContainerT >
		void tokenize(const std::string& str, ContainerT& tokens, const std::string& delimiters = " ", const bool trimEmpty = false)
		{
		   std::string::size_type pos, lastPos = 0;
		   while(true)
		   {
			  pos = str.find_first_of(delimiters, lastPos);
			  if(pos == std::string::npos)
			  {
				 pos = str.length();

				 if(pos != lastPos || !trimEmpty)
					tokens.push_back(ContainerT::value_type(str.data()+lastPos, (ContainerT::value_type::size_type)pos-lastPos ));

				 break;
			  }
			  else
			  {
				 if(pos != lastPos || !trimEmpty)
					tokens.push_back(ContainerT::value_type(str.data()+lastPos, (ContainerT::value_type::size_type)pos-lastPos ));
			  }

			  lastPos = pos + 1;
		   }
		};
*/
		static int levenshtein_distance(const std::string source, const std::string target);

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

		static int compare_string_X( const std::string& str, const std::string& str2 );


//@}
/** @name General Purpose Hash Function Algorithms (by Arash Partow, 2002, http://www.partow.net )
 * @{
 ******************************************************************************/
	public:
		static unsigned int hash_RS( const std::string& str );
		static unsigned int hash_JS( const std::string& str );
		static unsigned int hash_PJW( const std::string& str );
		static unsigned int hash_ELF( const std::string& str );
		static unsigned int hash_BKDR( const std::string& str );
		static unsigned int hash_SDBM( const std::string& str );
		static unsigned int hash_DJB( const std::string& str );
		static unsigned int hash_DEK( const std::string& str );
		static unsigned int hash_BP( const std::string& str );
		static unsigned int hash_FNV( const std::string& str );
		static unsigned int hash_AP( const std::string& str );


//@}
/** @name MD5 Functions
 * @{
 ******************************************************************************/
	public:
		static bool calculateMD5( const std::string& data, std::string& md5str );
		static bool calculateMD5( std::string& md5str, const char* format, ... );

		static void UUID( std::string& uuid_str );

//@}

	private:
		Utilities() { }

}; // class def

}; // namespace wosh

#endif //__WOSH_Core_Utilities_H__
